package com.example.mysql.学习笔记.高级.事务.多版本并发控制;

public class MVCC实现原理之ReadView_4 {
}
/**
 * 4. MVCC实现原理之ReadView   当某个事务查询时，到底返回那个版本的数据
 * MVCC的实现依赖于: 隐藏字段、Undo Log、ReadView
 * 4.1什么是ReadView
 * 在MVCC机制中，多个事务对同一个行记录进行更新会产生多个历史快照， 这些历史快照保存在UndoLog里。
 * ""如果一个事务想要查询这个行记录，需要读取哪个版本的行记录呢?""
 * 这时就需要用到ReadView了，它帮我们解决了行的可见性问题。
 * ReadView就是事务在使用MVCC机制进行快照读操作时产生的读视图。
 * 当事务启动时，会生成数据库系统当前的-个快照， InnoDB 为每个事务构造了一个数组，
 * 用来记录并维护系统当前  活跃事务的ID (“活跃'指的就是，启动了但还""没提交"")。
 *
 * ReadView和事务是一对一
 *
 */
/**
 * 4.2设计思路  只能用到 读已提交和可重复读的 隔离级别
 * 使用READ UNCOMMITTED 隔离级别的事务，由于可以读到未提交事务修改过的记录,
 *       所以直接读取记录的最新版本就好了。
 * 使用SERIALIZABLE(串行化)隔离级别的事务，InnoDB规定使用加锁的方式来访问记录。 读的已经是最新了
 * 使用READ COMMITTED 和REPEATABLE READ 隔离级别的事务,
 * 都必须保证读到已经提交了的事务修改过的记录。
 * 假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的,
 * 核心问题就是需要判断一下版本链中的哪个版本是当前事务可见的，
 * 这是ReadView要解决的主要问题。
 *
 * 这个ReadView中主要包含4个比较重要的内容,分别如下: .
 * 1. creator_trx_id,创建这个Read View的事务ID。
 *    说明:只有在对表中的记录做改动时(执行INSERT、 DELETE、 UPDATE这些语句时)
 *    才会为事务分配事务id, 否则在一个只读事务中的事务id值都默认为0。
 * 2. trx_ids,表示在生成ReadView时当前系统中  活跃的读写事务的事务id列表。
 * 3. up_limit_id,活跃的事务中  最小  的事务ID。
 * 4. low_limit_id,表示生成ReadView时系统中应该分配给下一个事务的id值。
 *   low_limit_id 是"系统最大"的事务id值，这里要注意是系统中的事务id,需要区别于正在活跃的事务ID。
 *      注意: low_limit_jid并不是trx_jds中的最大值，事务id是递增分配的。
 *      比如，现在有id为1，2, 3这三个事务，之后id为3的事务提交了。
 *      那么一个新的读事务在生成ReadView时，trx_ids就包括1和2，
 *      up_limit_id的值就是1， low_limit_id的值就是4。
 *
 *
 */
/**
 * 4.3
 * 的规则  看例子
 * 有了这个ReadView,这样在访问某条记录时，只需要按照下边的步骤判断记录的某个版本是否可见。
 * ●如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同，
 * 意味着当前事务在访问它自己修改过的记录，所以该版本可以被当前事务访问。
 * ●如果被访问版本的trx_id属性值小于ReadView中的up_limit_id值，
 *  表明生成该版本的事务在当前事务生成ReadView前已经提交，所以该版本可以被当前事务访问。
 * ●如果被访问版本的trx_id属性值大于或等于ReadView中的low_limit_id值，
 * 表明生成该版本的事务在当前事务生成ReadView后才开启，所以该版本不可以被当前事务访问。
 * ●如果被访问版本的trx_id属性值在ReadView的up_limit_id和low_limit_id之间，
 *  那就需要判断一下trx_id属性值是不是在trx_ids列表中。
 *      。如果在，说明创建ReadView时生成该版本的事务还是活跃的，该版本不可以被访问。
 *      。如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。
 *
 *
 */
/**
 * 4.4 MVCC整体操作流程
 * 了解了这些概念之后，我们来看下当查询一条记录的时候，系统如何通过MVCC找到它:
 * 1.首先获取事务自己的版本号，也就是事务ID;
 * 2.获取ReadView;
 * 3.查询得到的数据，然后与ReadView中的事务版本号进行比较;
 * 4.如果不符合ReadView规则，就需要从Undo Log中获取历史快照;
 * 5.最后返回符合规则的数据。
 *
 * 如果某个版本的数据对当前事务不可见的话，那就顺着版本链找到下一个版本的数据，
 * 继续按照上边的步骤判断可见性，依此类推，直到版本链中的最后-个版本。
 * 如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见，查询结果就不包含该记录。
 *
 * 在隔离级别为读已提交(Read Commit)时，
 * 一个事务中的每一次 SELECT查询都会重新获取一次 Read View。
 * 注意，此时同样的查询语句都会重新获取一次Read View,
 * 这时如果Read View不同，就可能产生不可重复读 或者幻读的情况。
 *
 * 当隔离级别为可重复读的时候，就避免了不可重复读,
 * 这是因为一个事务只在第一次SELECT的时候会获取一次Read View,
 * 而后面所有的SELECT都会复用这个Read View,
 *
 */
